package com.strive.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.strive.common.lock.DistributedLock;
import com.strive.common.model.base.PageResult;
import com.strive.common.model.dto.SysMenu;
import com.strive.common.model.dto.SysPower;
import com.strive.common.model.dto.SysPowerRole;
import com.strive.common.model.dto.SysRole;
import com.strive.common.model.po.SysPowerCodesPo;
import com.strive.common.service.impl.SuperServiceImpl;
import com.strive.user.mapper.*;
import com.strive.user.service.ISysMenuService;
import com.strive.user.service.ISysRoleMenuService;
import com.strive.user.service.ISysRoleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: bingcun.chen
 * @Date: 2022/3/7 15:25
 * @Version 1.0
 */
@Slf4j
@Service
public class SysRoleServiceImpl extends SuperServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {
    private final static String LOCK_KEY_ROLECODE = "rolecode:";

    @Resource
    private SysUserRoleMapper userRoleMapper;

    @Resource
    private SysRoleMenuMapper roleMenuMapper;

    @Autowired
    private DistributedLock lock;

    @Autowired
    private SysPowerMapper sysPowerMapper;

    @Autowired
    private ISysRoleMenuService sysRoleMenuService;

    @Autowired
    private SysPowerRoleMapper sysPowerRoleMapper;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveRole(SysRole sysRole) throws Exception {
        String roleCode = sysRole.getCode();
        super.saveIdempotency(sysRole, lock
                , LOCK_KEY_ROLECODE+roleCode, new QueryWrapper<SysRole>().eq("code", roleCode), "角色code已存在");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteRole(Long id) {
        //删除角色表
        baseMapper.deleteById(id);
        //删除角色菜单表
        roleMenuMapper.delete(id, null);
        //删除用户角色表
        userRoleMapper.deleteUserRole(null, id);
        //删除角色权限表
        LambdaQueryWrapper<SysPowerRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysPowerRole::getRoleId, id);
        sysPowerRoleMapper.delete(wrapper);
    }

    @Override
    public PageResult<SysRole> findRoles(Map<String, Object> params) {
        Integer curPage = MapUtils.getInteger(params, "pageNum");
        Integer limit = MapUtils.getInteger(params, "pageSize");
        Page<SysRole> page = new Page<>(curPage == null ? 0 : curPage, limit == null ? -1 : limit);
        List<SysRole> list = baseMapper.findList(page, params);
        buildMenusAndPowers(list);
        return PageResult.<SysRole>builder().data(list).status(200).count(page.getTotal()).build();
    }

    private void buildMenusAndPowers(List<SysRole> list) {
        //遍历角色设置权限
        for (SysRole sysRole : list){
            Set<String> sets = new HashSet<>();
            sets.add(sysRole.getCode());
            List<SysMenu> menusList = sysRoleMenuService.findMenusByRoleCodes(sets,null);
            if(CollectionUtils.isNotEmpty(menusList)){
                List<SysPowerCodesPo> menuAndPowersList = Lists.newArrayList();
                for (SysMenu sysMenu : menusList) {
                    SysPowerCodesPo sysPowerCodesPo = new SysPowerCodesPo();
                    sysPowerCodesPo.setMenuId(sysMenu.getId());
                    List<SysPower> powersByRoles = sysPowerMapper.findPowersByRoles(sets);
                    if(CollectionUtils.isNotEmpty(powersByRoles)){
                        sysPowerCodesPo.setPowers(powersByRoles.stream().map(ns->ns.getId()).collect(Collectors.toList()));
                    }
                    menuAndPowersList.add(sysPowerCodesPo);
                }
                sysRole.setMenuAndPowers(menuAndPowersList);
            }
        }
    }

    @Override
    @Transactional
    public void saveOrUpdateRole(SysRole sysRole) throws Exception {
        if (sysRole.getId() == null) {
            this.saveRole(sysRole);
        } else {
            baseMapper.updateById(sysRole);
        }
    }

    @Override
    public List<SysRole> findAll() {
        List<SysRole> allRoles = baseMapper.findAll();
        buildMenusAndPowers(allRoles);
        return allRoles;
    }

}
